// Class FileValues
// Read and write values of variables on streams
// Author: Bernardo Mello
// Date: Jan/Jun 2010

//using namespace std;
#ifndef FILEVALUES_H_
#define FILEVALUES_H_
#include <vector>
#include <iostream>
#include <cstdlib>

class FileValues {
public:
	FileValues(std::string comStr = "#") :
		comStr(comStr) {
	}

	~FileValues() {
		clear();
	}

	void clear();

	template<class T> void addParam(std::string name, T& pVar);

	void loadParamVars(std::istream& input);

	void writeParamVars(std::ostream& output, bool printTime = true);
private:

	class base_keepVar;

	std::vector<base_keepVar*> vars;
	std::string comStr; //String to be placed before the parameter name


	template<class T>
	class keepVar;
	/*template<class T> class keepVar<vector<T> > : public keepVar<vector<T> > {
	 };*/
};

template<class T>
std::ostream& operator<<(std::ostream& output, std::vector<T>& var) {
	output << "[ ";
	for (size_t i = 0; i != var.size(); i++)
		output << var[i] << " ";
	return output << "]";
}

template<class T>
std::istream& operator>>(std::istream& input, std::vector<T> &var) {
	std::string s;
	input >> s;
	if (s.compare("[") != 0) {
		std::cerr << "Vector must be inside brackets. Ex: [ 0 3 ] \n";
		exit(0);
	}
	var.clear();
	do {
		T v;
		input >> v;
		if (!input.fail())
			var.push_back(v);
	} while (!input.fail());
	input.clear();
	return input;
}

template<class T> void FileValues::addParam(std::string name, T& pVar) {
	vars.push_back(new keepVar<T> (comStr + name, pVar));
}

class FileValues::base_keepVar {
public:
	virtual void readParam(std::istream& input) = 0;
	virtual void writeParam(std::ostream& output) = 0;
};

template<class T>
class FileValues::keepVar: public base_keepVar {
private:
	std::string name;
	T& pVar;
public:
	keepVar(std::string name, T& pVar) :
		name(name), pVar(pVar) {
	}

	void readParam(std::istream& input) {
		findParam(input, name);
		input >> pVar;
	}

	void writeParam(std::ostream& output) {
		output << name << " " << pVar << "\n";
	}

private:
	void findParam(std::istream& input, std::string name) {
		std::string s;
		while (input >> s && s.compare(name) != 0)
			;
		if (s.compare(name) != 0) {
			std::cerr << "Parameter " << name << " not found in input file\n";
			exit(0);
		}
	}

};

#endif //FILEVALUES_H
